#include "Graphs.h"
#include <sstream>
#include <string>
#include <iostream>
void Graphs::generateGraphs( ){
	controlFlowGraph();
	hierarchicalTaskGraphs();
	generateDeclarationsTable();
	dataFlowGraph();
	dataDependenceGraph();
	controlDependenceGraph(1, nBlocks, 0);
//	cout << endl;
//	for(int i = 0; i < basicBlocksDeclarations.size(); i++){
//	    cout << endl << i;
//	    for(int j = 0; j < basicBlocksDeclarations[i].size(); j++)
//	        cout<< " " << basicBlocksDeclarations[i][j];
//	}
//    cout << endl << searchDec(3, "j");
    cdg.print();
//	cfg.print();
//	htg.print();
}

int Graphs::searchDec(int position, string val){
    for ( int i = position - 1; i > 0; i-- ){
        for( int j = 0; j < basicBlocksDeclarations[i].size(); j++){
            if( basicBlocksDeclarations[i][j] == val )
                return i;
        }
    }
    return -1;
}

int Graphs::findBlockByLine( int line ){
	map<int, int>::iterator it = blocks.begin();
	while ( it != blocks.end() ){
		if ( (*it).second == line )
    		return (*it).first;
    	it++;
	}
	return -1;
}

int Graphs::getLabel( string label ){
    stringstream ss(label);
    int ret = -1;
    if ( "EOF" != label ){
        ss >> ret;
    }
    return ret;
}

void Graphs::generateDeclarationsTable( ){
    int lineNumber = 0;
    basicBlocksDeclarations = vector< vector<string> >( nBlocks, vector<string>() );
    for( int i = 1; i < nBlocks; i++ ){
        int blockSize = blocks[i + 1] - blocks[i];
        for( int j = 0; j < blockSize; j++ ){
            if( instructions[lineNumber].getRhs() != "goto" )
                basicBlocksDeclarations[i].push_back(instructions[lineNumber].getResult());
            lineNumber++;
        }
    }
}

int Graphs::findDependence( string value, int position ){
    for( int i = position - 1; i >= 0; i--){
        if( instructions[i].getResult() == value && instructions[i].getRhs() != "goto")
            return i + 1;
    }
    return -1;
}

void Graphs::controlDependenceGraph( int ini, int end, int root ){
    int label1, label2;
    int toVertex, fromVertex;
	for( int i = ini; i < end; i++){
		if ( instructions[ blocks[i] ].getLhs() == "if" ){
			if (root != i )	cdg.insertEdge(root, i);
			cdg.insertEdge( i, i + 1 );
			label1 = getLabel( instructions[ blocks[i] ].getResult() );
		    if( label1 != -1 )
		        toVertex = findBlockByLine(labels[label1]);
		    else
		        toVertex = blocks.rbegin()->first;
		    int ii = blocks[ toVertex ] - 1;
		    fromVertex = i;
		    if( instructions[ii].getRhs() == "goto" ){
		    	label2 = getLabel( instructions[ii].getResult() );
		    	if( toVertex < findBlockByLine(labels[label2]) ){
					cdg.insertEdge(i, toVertex );
					i = toVertex;
		    	}
		 		else {
			    	cdg.insertEdge(root, toVertex);		 		
 					i = toVertex - 1;
		 		}
			}
			if(toVertex - fromVertex > 2 ){
				controlDependenceGraph(fromVertex + 1, toVertex, fromVertex + 1);
			}
		} else {
			if (root != i )	cdg.insertEdge(root, i);
		}
    }
}

void Graphs::dataDependenceGraph(){
    int block;
    bool noDependency = true;
    for(int i = 1; i < blocks.size(); i++){
        noDependency = true;
        for( int j = blocks[i]; j < blocks[i+1]; j++){
            block = searchDec( i, instructions[j].getLhs() );
            if( block != -1 ){
                noDependency = false;
                ddg.insertEdge( block, i );
            }
            block = searchDec( i, instructions[j].getRhs() );
            if( block != -1 ){
                noDependency = false;
                ddg.insertEdge( block, i );
            }
            if( ( noDependency ) && ( instructions[j].getRhs() != "goto" ) ){
               ddg.insertEdge( 0, i );
            }
        }
    }
}

void Graphs::dataFlowGraph(){
    int line = 0;
    bool noDependency = true;
    for( int i = 0; i < instructions.size(); i++){
        line = findDependence(instructions[i].getLhs(), i);
        if( line != -1 ){
            dfg.insertEdge(line, i + 1);
            noDependency = false;
        }
        line = findDependence(instructions[i].getRhs(), i);
        if( line != -1 ){        
            dfg.insertEdge(line, i + 1);
            noDependency = false;
        }
        if( noDependency && instructions[i].getRhs() != "goto" ){
            dfg.insertEdge(0, i + 1);
        }
        noDependency = true;
    }
}

void Graphs::controlFlowGraph(){
    int fromVertex = 1, toVertex = 1;
    int i, label;
    cfg.insertEdge( 0, 1 );
    while ( fromVertex < blocks.rbegin()->first ) {
        i = blocks[fromVertex];
        if( instructions[i].getRhs() == "goto" ) {
            if ( instructions[i].getLhs() == "if" ){
				toVertex = fromVertex + 1;
	            cfg.insertEdge( fromVertex, toVertex );            
            }
            label = getLabel( instructions[i].getResult() );
            if( label != -1 )
                toVertex = findBlockByLine(labels[label]);
            else
                toVertex = blocks.rbegin()->first;
            cfg.insertEdge( fromVertex, toVertex );
                
        } else {
            i = blocks[ ( fromVertex + 1 ) ] - 1;
            if( instructions[i].getRhs() == "goto" ) {
                label = getLabel( instructions[i].getResult() );
                if( label != -1 )
                    toVertex = findBlockByLine( labels[label] );
                else
                    toVertex = blocks.rbegin()->first;
                if( ( blocks[toVertex] < blocks[fromVertex] ) && ( ( fromVertex - toVertex ) == 1 ) )
                    cfg.insertBidirectionalEdge( fromVertex, toVertex );
                else
                    cfg.insertEdge( fromVertex, toVertex );
            } else {
                toVertex = fromVertex + 1;
                cfg.insertEdge( fromVertex, toVertex );
            }
        }
        fromVertex++;
    }
}

void Graphs::hierarchicalTaskGraphs(){
	int fromVertex = 1, toVertex = 1;
    int i, label;
    htg.insertEdge( 0, 1 );
    while ( fromVertex < blocks.rbegin()->first ) {
        i = blocks[fromVertex];
        if( instructions[i].getRhs() == "goto" ) {
            if ( instructions[i].getLhs() == "if" ){
				toVertex = fromVertex + 1;
	            htg.insertEdge( fromVertex, toVertex );            
            }
            label = getLabel( instructions[i].getResult() );
            if( label != -1 )
                toVertex = findBlockByLine(labels[label]);
            else
                toVertex = blocks.rbegin()->first;
            htg.insertEdge( fromVertex, toVertex );
            if( ( toVertex - fromVertex ) > 2 ){
                if( instructions[( blocks[toVertex] - 1 )].getRhs() == "goto" ){
                    if( instructions[blocks[fromVertex]].getLabel() == getLabel( instructions[( blocks[toVertex] - 1 )].getResult() ) )
                        htg.insertBidirectionalEdge(fromVertex, fromVertex + 1);
                    else
                        htg.insertBidirectionalEdge(fromVertex + 1, toVertex );
                }
            	fromVertex += 2;
            }
        } else {
            i = blocks[ ( fromVertex + 1 ) ] - 1;
            if( instructions[i].getRhs() == "goto" ) {
                label = getLabel( instructions[i].getResult() );
                if( label != -1 )
                    toVertex = findBlockByLine( labels[label] );
                else
                    toVertex = blocks.rbegin()->first;
                if( ( blocks[toVertex] < blocks[fromVertex] ) && ( ( fromVertex - toVertex ) == 1 ) )
                    htg.insertBidirectionalEdge( fromVertex, toVertex );
                else
                    htg.insertEdge( fromVertex, toVertex );
                
            } else {
                toVertex = fromVertex + 1;
                htg.insertEdge( fromVertex, toVertex );
            }
        }
        fromVertex++;
    }
}
